
import threading
import asyncio
from db_setting import *
import aiomysql
import aioredis

class DataBasePool:

    instance = None
    init_flag = False

    def __new__(cls, *args, **kwargs):
        # 1. 判断类属性是否是空对象
        if cls.instance is None:
            # 2. 调用父类的方法，为第一个对象分配空间
            cls.instance = super().__new__(cls)

        # 3. 返回类属性保存的对象引用
        return cls.instance

    def __init__(self, loop=None):

        if not DataBasePool.init_flag:
            
            print("初始化数据库")
            if loop == None:
                loop = asyncio.new_event_loop()
                t = threading.Thread(target=self.thread_running_loop, args=(loop,))     
                t.start()

            self.loop = loop
            self.start_pools()
            DataBasePool.init_flag = True

    def thread_running_loop(self, loop):#开启loop
        '''
            set_event_loop(eventloop对象)将eventloop对象指定为当前线程的eventloop(非主线程的事件循环)
        '''
        asyncio.set_event_loop(loop)    #在此线程中设置一个新的事件循环,默认情况下事件循环是主线程的
        loop.run_forever()

    async def make_master_pool(self):

        self.master_pool = await aiomysql.create_pool(
                                                host=MASTER_DB_HOST, 
                                                port=MASTER_DB_PORT,
                                                user=MASTER_DB_USER,
                                                password=MASTER_DB_PASS_WORD,
                                                db=MASTER_DB_NAME,
                                                autocommit=False,
                                                loop=self.loop
                                                )
        print("mysql_master线程池开启完毕~~~")

    async def make_slave_pool(self):

        self.slave_pool = await aiomysql.create_pool(
                                                host=SLAVE_DB_HOST, 
                                                port=SLAVE_DB_PORT,
                                                user=SLAVE_DB_USER,
                                                password=SLAVE_DB_PASS_WORD,
                                                db=SLAVE_DB_NAME,
                                                autocommit=False,
                                                loop=self.loop
                                                )
        print("mysql_slave线程池开启完毕~~~")

    
    async def make_redis_pool(self):
        print('redis_pool**********************')
        address = f'redis://{REDIS_DB_HOST}:{REDIS_DB_PORT}'
        self.redis_pool = await aioredis.create_redis_pool(
                                                            address,
                                                            db=0,
                                                            password=REDIS_DB_PASS_WORD,
                                                            encoding='utf-8',
                                                            loop=self.loop,                                        
                                                          )

        print('redis线程池开启完毕~~~')

    def start_pools(self):#启动pools
        '''
            在db_setting文件配置要开启的线程池
        '''
        if MASTER_DB_POOL:
            asyncio.run_coroutine_threadsafe(self.make_master_pool(), self.loop)
        if SLAVE_DB_POOL:
            asyncio.run_coroutine_threadsafe(self.make_slave_pool(), self.loop)
        if REDIS_DB_POOL:
            asyncio.run_coroutine_threadsafe(self.make_redis_pool(), self.loop)
        
        if not any((MASTER_DB_POOL, SLAVE_DB_POOL, REDIS_DB_POOL)):

            raise ValueError('请在db_setting中打开数据库链接')



class AioMysqlPoolMethod:

    '''
        封装了aioMysqlPool的基础方法
    '''

    def __init__(self, pool):

        self.pool = pool

    async def fetchone(self, sql, args=None):
        '''
        查询单个
        '''
        async with self.pool.acquire() as conn:
            await conn.ping()

            async with conn.cursor(aiomysql.DictCursor) as cur:
                if args==None:

                    await cur.execute(sql)
                else:
                    await cur.execute(sql,args)

                result_info = await cur.fetchone()
        
        return result_info

    async def fetchall(self, sql, args= None):
        
        '''
        查询所有

        '''
        async with self.pool.acquire() as conn:
            await conn.ping()

            async with conn.cursor(aiomysql.DictCursor) as cur:
                if args==None:

                    await cur.execute(sql)
                else:
                    await cur.execute(sql,args)

                result_info = await cur.fetchall()
        
        return result_info


    async def execute(self, sql,args=None):
    
        '''
        执行单条sql

        '''
        async with self.pool.acquire() as conn:
            
            await conn.ping()

            async with conn.cursor(aiomysql.DictCursor) as cur:
                if args==None:

                    await cur.execute(sql)
                else:
                    await cur.execute(sql,args)

                await conn.commit()
        
        return True

    async def executemany(self, sql, args):
    
        '''
        执行多条sql

        '''
        async with self.pool.acquire() as conn:
            
            await conn.ping()

            async with conn.cursor(aiomysql.DictCursor) as cur:

                await cur.executemany(sql,args)

                await conn.commit()
        
        return True


    
